#!/usr/bin/python
"A Python interface to Google calendars."
try:
  from xml.etree import ElementTree # for Python 2.5
except ImportError:
  from elementtree import ElementTree
import gdata.calendar.service
import gdata.service
import atom.service
import gdata.calendar
import atom
import getopt
import sys
import string
import time
import getpass
import re

def utext(element):
    '''Get an element's text attribute, forcefully decode it from UTF-8,
       and return Unicode.'''
    return element.text.decode('utf8')

class gcal:
    "A focal point for communication with the Google Calendar service."
    user = None
    service = None
    calendar = None
    eventFeedURI = None
    def __init__(self, user, passwd = None):
        '''Supply the Google account user's email address and optionally, password.
           If you omit the password we'll prompt for it, hiding your input.'''
        self.user = user
        if not passwd:
            passwd = getpass.getpass()
        self.service = gdata.calendar.service.CalendarService(self.user, passwd, 'CEDU Record Mangler')
        self.service.ProgrammaticLogin()
    def getEventFeedLink(self, calEntry):
        '''Internal function. Find the event feed link in a gdata calendar entry.'''
        for link in calEntry.link:
            if re.search('#eventFeed$', link.rel):
                return link.href
    def calendars(self, which = 'all'):
        '''Return a list of calendars (names) for the user.
           Pass in an argument to control which calendars are returned.
             'all' -> all calendars, owned or imported (default)
             'own' -> calendars the user owns'''
        if which == 'all':
            calFeed = self.service.GetAllCalendarsFeed()
        elif which == 'own':
            calFeed = self.service.GetOwnCalendarsFeed()
        if isinstance(calFeed, gdata.calendar.CalendarListFeed):
            return [utext(calEntry.title) for calEntry in calFeed.entry]
        else:
            print >> sys.stderr, calFeed  # dump result
            sys.exit(1)
    def selectCalendar(self, name):
        '''Select a calendar, by name, to work with events.
           We'll return True if we located the calendar, False if not.
           You can specify just the beginning of the name, and we'll
           find the first calendar that matches.'''
        calFeed = self.service.GetAllCalendarsFeed()
        for cal in calFeed.entry:
            if utext(cal.title).startswith(name):
                self.calendar = utext(cal.title)
                self.eventFeedURI = self.getEventFeedLink(cal)
                if not self.eventFeedURI:
                    print >> sys.stderr, 'I could not find the event calFeed for', self.calendar
                    print >> sys.stderr, 'Calendar not selected.'
                    self.calendar = None
                    return False
                break
        if self.calendar.startswith(name):
            return True
    def events(self):
        '''Retrieve a page of events from the current calendar (see selectCalendar).
           By default, the server will return 25 events at a time.
           We'll return a duple: (1) the total number of events reported
           and (2) a list of the events (just the titles) returned.'''
        if self.eventFeedURI:
            evFeed = self.service.GetCalendarEventFeed(self.eventFeedURI)
            return (evFeed.total_results, [utext(event.title) for event in evFeed.entry])
    def insertEvent(self, title, content, where, start_time, end_time):
        '''Insert a new event into the current calendar (see selectCalendar).
           times are strings in ISO time format yyyy-mm-ddThh:mm:ss.000Z .
           Return a copy of the new event.'''
        event = gdata.calendar.CalendarEventEntry()
        event.title = atom.Title(text=title)
        event.content = atom.Content(text=content)
        event.where.append(gdata.calendar.Where(value_string=where))
        event.when.append(gdata.calendar.When(start_time=start_time, end_time=end_time))
        new_event = self.service.InsertEvent(event, self.eventFeedURI)
        #print 'New single event inserted: %s' % (new_event.id.text,)
        #print '\tEvent edit URL: %s' % (new_event.GetEditLink().href,)
        #print '\tEvent HTML URL: %s' % (new_event.GetHtmlLink().href,)
        return new_event
